#!/usr/bin/env python3

'''
    @author : walker
    @time : 2019/10/9
    @description : 泰坦尼克乘客获救预测
'''

import pandas as pd
import numpy as np
from pandas import Series,DataFrame
from config import *
from analysis_train_data import *
from sklearn.linear_model import LinearRegression
#训练集交叉验证，得到平均值
from sklearn.model_selection import KFold
#引入逻辑回国
from sklearn.linear_model import LogisticRegression
from sklearn import model_selection
#引入随机森林算法
from sklearn.ensemble import RandomForestClassifier

def read_data():
    '''
        读取训练数据、测试数据
        param:
            None
        return:
            train_data : 训练数据集
            test_data : 测试数据集
    '''
    #创建新的字段Age_param用来为年龄分段
    # train_data.loc[(train_data['Age'] > 0) & (train_data['Age'] <= 3),'Age_param'] = 1
    # train_data.loc[(train_data['Age'] > 3) & (train_data['Age'] <= 6),'Age_param'] = 2
    # train_data.loc[(train_data['Age'] > 6) & (train_data['Age'] <= 11),'Age_param'] = 3
    # train_data.loc[(train_data['Age'] > 11) & (train_data['Age'] <= 16),'Age_param'] = 4
    # train_data.loc[(train_data['Age'] > 16) & (train_data['Age'] <= 28),'Age_param'] = 5
    # train_data.loc[(train_data['Age'] > 28) & (train_data['Age'] <= 40),'Age_param'] = 6
    # train_data.loc[(train_data['Age'] > 40) & (train_data['Age'] <= 65),'Age_param'] = 7
    # train_data.loc[(train_data['Age'] > 65) & (train_data['Age'] <= 90),'Age_param'] = 7

    # 读取数据
    train_data = pd.read_csv(train_data_url)
    test_data = pd.read_csv(test_data_url)

    return train_data,test_data

def linear_model(train_data,predictors):
    '''
        线性回归算法,KFold采取的是shuffle为False的切割数据方法
        params：
            train_data
            predictors ：可用的特征名
        return:
            accuracy : 正确率
    '''
    #初始化线性回归算法
    linear_alg = LinearRegression()
    #样本平均划分成三分，三折交叉验证
    kf = KFold(n_splits=3,shuffle=False,random_state=1)

    #设定predictions list
    predictions = []
    for train,test in kf.split(train_data):
        #获取到训练集中的训练数据
        train_predictors = (train_data[predictors].iloc[train,:])
        #获取到训练数据的生存情况
        train_target = train_data["Survived"].iloc[train]

        #训练模型
        linear_alg.fit(train_predictors,train_target)

        #测试模型
        test_predictions = linear_alg.predict(train_data[predictors].iloc[test,:])
        predictions.append(test_predictions)
    #将测试后的数据连接到一起
    predictions = np.concatenate(predictions,axis=0)

    #将生存的可能性由0~1概率区间转为0或1
    predictions[predictions > 0.5] = 1
    predictions[predictions <= 0.5] = 0

    #测试线性非随机模型的准确性
    accuracy = sum(predictions == train_data['Survived']) / len(predictions)
    print("线性回归准确率为：",accuracy)
    return linear_alg

def linear_random_model(train_data,predictors):
    '''
        线性回归算法,KFold采取的是shuffle为True的切割数据方法
        params：
            train_data
            predictors ：可用的特征名
        return:
            accuracy : 正确率
    '''
    #初始化线性回归算法
    linear_random_alg = LinearRegression()
    #样本平均划分成三分，三折交叉验证
    # random_state可以随意设置，这是一个随机值，随着替换则下面的train,test数据集也都会被替换掉
    kf = KFold(n_splits=3,shuffle=True,random_state=2)

    #设定predictions list
    predictions = [0 for i in range(len(train_data))]
    accuracy = 0
    for train,test in kf.split(train_data):
        #获取到训练集中的训练数据
        # print(test)
        train_predictors = (train_data[predictors].iloc[train,:])
        #获取到训练数据的生存情况
        train_target = train_data["Survived"].iloc[train]
        predictions.append(test)

        #训练模型
        linear_random_alg.fit(train_predictors,train_target)

        #测试模型
        test_predictions = linear_random_alg.predict(train_data[predictors].iloc[test,:])
        #将概率值大于0.5的设置为1，小于0.5的设置为0
        test_predictions[test_predictions > 0.5] = 1
        test_predictions[test_predictions <= 0.5] = 0
        #将所有正确的值加到accuray中
        accuracy += sum(test_predictions == train_data['Survived'].iloc[test])
    print("线性回归shuffle为真的准确率为：",accuracy / len(train_data["Survived"]))
    return linear_random_alg

def logic_model(train_data,predictors):
    '''
        逻辑回归算法
        params :
            train_data : 数据
            predictors ：可用的特征名
        return :
            accuracy : 正确率
    '''
    logic_alg = LogisticRegression(solver='liblinear',random_state = 1)
    re = logic_alg.fit(train_data[predictors],train_data['Survived'])

    #使用sklearn中的交叉验证函数获取预测准确率分数
    scores = model_selection.cross_val_score(logic_alg,train_data[predictors],train_data["Survived"],cv=3)

    print("逻辑回归准确率为：",scores.mean())
    return logic_alg

def random_forest_model(train_data,predictors):
    '''
        随机森林算法
        params :
            train_data : 数据
            predictors ：可用的特征名
        return :
            accuracy : 正确率
    '''
    #10棵决策树，停止条件，样本个数为2，叶子节点个数为1
    random_forest_alg = RandomForestClassifier(random_state=1,n_estimators=20,min_samples_split=3,min_samples_leaf=2)

    #
    kf = KFold(n_splits=5,shuffle=False,random_state=1)
    scores = model_selection.cross_val_score(random_forest_alg,train_data[predictors],train_data["Survived"],cv = kf)
    # print("随机森林分数为：",scores)
    print("随机森林平均分数为：",scores.mean())
    return random_forest_alg

def main():
    #读取训练集测试集
    train_data,test_data = read_data()
    print(train_data.head())
    # print(test_data.head())

    # 对titanic数据进行绘图分析
    analysis_titanic = analysis_titanic_train_data(train_data)

    # print(train_data.info())
    # print(train_data['Age'].describe())
    # print(train_data['Embarked'].describe())

    # 对年龄分布进行数据分析
    # analysis_titanic.age_analysis()
    #Age特征中的缺失值使用Age的中位数进行填充
    train_data['Age'] = train_data['Age'].fillna(train_data['Age'].median())

    #对上船地址进行分析
    # analysis_titanic.embarked_analysis()
    # 对Embarked的数据进行填充
    train_data['Embarked'] = train_data['Embarked'].fillna('S')
    # print(train_data.info())

    #先选取简单的可用的输入特征
    predictors = ["Pclass","Age","SibSp","Parch","Fare"]

    # 线性回归算法,KFold采取的是shuffle为False的切割数据方法
    linear_alg = linear_model(train_data,predictors)

    # 线性回归算法,KFold采取的是shuffle为True的切割数据方法
    linear_random_alg = linear_random_model(train_data,predictors)

    # 逻辑回归算法
    logic_alg = logic_model(train_data,predictors)

    #随机森林算法
    random_forest_alg = random_forest_model(train_data,predictors)

    print("---------------------这里是分割线---------------------")

    # 加入性别信息
    #将性别信息处理成0-1格式
    train_data.loc[train_data["Sex"] == "male","Sex"] = 1
    train_data.loc[train_data["Sex"] == "female","Sex"] = 0

    #将embarked处理成0，1，2数据格式
    train_data.loc[train_data["Embarked"] == "S","Embarked"] = 0
    train_data.loc[train_data["Embarked"] == "C","Embarked"] = 1
    train_data.loc[train_data["Embarked"] == "Q","Embarked"] = 2

    #将predictors加入Sex和Embarked信息
    predictors = ["Pclass","Sex","Age","SibSp","Parch","Fare","Embarked"]

    # 使用不同模型去预测
    # 线性回归算法,KFold采取的是shuffle为False的切割数据方法
    # 线性回归算法,KFold采取的是shuffle为False的切割数据方法
    linear_alg = linear_model(train_data,predictors)
    # 线性回归算法,KFold采取的是shuffle为True的切割数据方法
    linear_random_alg = linear_random_model(train_data,predictors)
    # 逻辑回归算法
    logic_alg = logic_model(train_data,predictors)
    #随机森林算法
    random_forest_alg = random_forest_model(train_data,predictors)

    print("---------------------以下是对test_data进行数据处理和Survived预测---------------------")
    # 对test_data的Age和Embarked特征进行数据填充
    test_data["Age"] = test_data["Age"].fillna(test_data["Age"].median())
    test_data["Embarked"] = test_data["Embarked"].fillna('S')
    #Fare列中的缺失值用Fare最大值进行填充
    test_data["Fare"] = test_data["Fare"].fillna(test_data["Fare"].max())

    # 加入性别信息
    #将性别信息处理成0-1格式
    test_data.loc[test_data["Sex"] == "male","Sex"] = 1
    test_data.loc[test_data["Sex"] == "female","Sex"] = 0

    #将embarked处理成0，1，2数据格式
    test_data.loc[test_data["Embarked"] == "S","Embarked"] = 0
    test_data.loc[test_data["Embarked"] == "C","Embarked"] = 1
    test_data.loc[test_data["Embarked"] == "Q","Embarked"] = 2

    test_features = ["Pclass","Sex","Age","SibSp","Parch","Fare","Embarked"]

    #构造测试集的Survived列，
    test_data["Survived"] = -1
    test_predictors = test_data[test_features]
    test_data["Survived"] = logic_alg.predict(test_predictors)

    print(test_data["Survived"])
    # print(len(test_data["Survived"]))






























if __name__ == '__main__':
    main()
